import type {
    GridApi,
    CellContextMenuEvent
} from '@ag-grid-community/core';

export interface MenuEntryDefinition {
    label: string;
    text: string;
    callback: (context: CellContextMenuEvent | undefined) => void;
    enabled?: (context: CellContextMenuEvent | undefined) => boolean;
}

interface MenuEntry extends MenuEntryDefinition {
    element: HTMLElement;
    clickHandler: (e: MouseEvent) => void;
}

export const defaultMenuEntries: MenuEntryDefinition[] = [
    {
        label: "edit",
        text: gettext("编辑"),
        callback: (context) => {
            if (!context || context.rowIndex == null) return;
            context.api.startEditingCell({
                rowIndex: context.rowIndex,
                colKey: context.column
            });
        },
        enabled: (context) => context?.colDef.editable === true
    },

    {
        label: "copy",
        text: gettext("复制"),
        callback: (context) => {
            if (!context) return;
            navigator.clipboard.writeText(String(context.value ?? ""));
        },
        enabled: (context) => {
            // Check browser support and cell content existence
            const canCopy = 'clipboard' in navigator;
            return !!context && canCopy && context.value != null;
        }
    }

]


export class GridContextMenu {
    private menu: HTMLElement;
    private api: GridApi;
    private context: CellContextMenuEvent | undefined = undefined;
    private menuEntries: MenuEntry[] = [];

    constructor(api: GridApi, menuEntriesDefs: MenuEntryDefinition[]) {
        this.api = api;
        
        this.menu = document.createElement('div');
        this.menu.classList.add(
            "tw:hidden",
            "tw:fixed", "tw:z-[3]",
            "tw:w-56", "tw:bg-base-100", "tw:rounded-xl", "tw:shadow", "tw:border",
            "tw:menu",
        );
        this.menu.setAttribute('data-ag-grid-context-menu', '');
        this.menu.append(document.createElement("ul"));
        
        document.body.appendChild(this.menu);
        this.destroy = this.destroy.bind(this);
        
        // Create menu entries from definitions
        menuEntriesDefs.forEach(def => this.addMenuEntry(def));
        
        document.addEventListener('click', this.destroy);
        document.addEventListener('scroll', this.destroy);
    }
    
    public onCellContextMenu(event: CellContextMenuEvent) {
        const mouse_event = event.event as MouseEvent;
        if (!mouse_event) return;
        this.context = event;
        this.showMenu(mouse_event.pageX, mouse_event.pageY);
    }

    private addMenuEntry(entryDef: MenuEntryDefinition) {
        const { label, text, callback, enabled } = entryDef;
        const entryElem = document.createElement("li");
        entryElem.setAttribute("data-ag-grid-context-menu-entry", label);
        
        const aElem = document.createElement("a");
        aElem.innerText = text;

        const clickHandler = (e: MouseEvent) => {
            e.stopPropagation();
            callback(this.context);
            this.destroy();
        };

        aElem.addEventListener("click", clickHandler);
        entryElem.append(aElem);
        this.menu.firstElementChild!.append(entryElem);

        // Store the entry information with enablement check
        this.menuEntries.push({
            ...entryDef,
            element: entryElem,
            clickHandler,
            enabled: enabled || (() => true) // Default to always enabled
        });
    }

    private showMenu(x: number, y: number) {
        this.menu.classList.remove('tw:hidden');

        // Update menu entries based on context
        this.menuEntries.forEach(entry => {
            const isEnabled = entry.enabled!(this.context);
            if (!isEnabled) {
                this.disableEntry(entry);
            } else {
                this.enableEntry(entry);
            }
        });
        
        // Position adjustment remains the same
        const menuRect = this.menu.getBoundingClientRect();
        const windowWidth = window.innerWidth;
        const windowHeight = window.innerHeight;

        if (x + menuRect.width > windowWidth) {
            x = windowWidth - menuRect.width;
        }

        if (y + menuRect.height > windowHeight) {
            y = windowHeight - menuRect.height;
        }

        this.menu.style.left = `${x}px`;
        this.menu.style.top = `${y}px`;
    }

    private disableEntry(entry: MenuEntry) {
        const aElem = entry.element.querySelector('a');
        if (aElem) {
            entry.element.classList.add("tw:menu-disabled");
            aElem.removeEventListener("click", entry.clickHandler);
        }
    }

    private enableEntry(entry: MenuEntry) {
        const aElem = entry.element.querySelector('a');
        if (aElem) {
            entry.element.classList.remove("tw:menu-disabled");
            aElem.addEventListener("click", entry.clickHandler);
        }
    }

    private destroy() {
        // Clean up remains the same
        this.menuEntries.forEach(entry => {
            const aElem = entry.element.querySelector('a');
            if (aElem) {
                aElem.removeEventListener("click", entry.clickHandler);
            }
        });

        this.menu.classList.add('tw:hidden');
        this.menu.remove();
        document.removeEventListener('click', this.destroy);
        document.removeEventListener('scroll', this.destroy);
    }
}
